﻿using SharpDX.Direct2D1;
using SharpDX.DXGI;
using SharpDX.Mathematics.Interop;
using SharpDX.WIC;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;

namespace RenderDemo
{
    public class SharpDXWicControl : FrameworkElement
    {
        #region 属性

        #region Child
        /// <summary>
        /// 画图可视化树
        /// </summary>
        private DrawingVisual drawingVisual = new DrawingVisual();
        protected override int VisualChildrenCount => 1;
        protected override Visual GetVisualChild(int index) => drawingVisual;
        #endregion Child
        //单个像素数据长度(字节)
        private int VarPixel = 4;

        #region 渲染
        //D2D工厂
        SharpDX.Direct2D1.Factory D2DFactory = new SharpDX.Direct2D1.Factory();

        // D2D图片工厂
        ImagingFactory D2DImageFactory = new ImagingFactory();

        //D2D图片
        private SharpDX.WIC.Bitmap D2DBitmap { get; set; }

        /// <summary>
        ///  渲染目标属性
        /// </summary>
        private RenderTargetProperties RenderTargetProperties { get; set; }

        //渲染目标
        WicRenderTarget D2DRenderTarget;
        #endregion
        #endregion

        #region 构造
        public SharpDXWicControl()
        {
            this.AddVisualChild(drawingVisual);

        }

        /// <summary>
        /// 归一化
        /// </summary>
        /// <param name="imagedata"></param>
        /// <param name="maxval"></param>
        /// <param name="gray"></param>
        private void Normalization(ref byte[] imagedata, byte maxval = 255, bool gray = false)
        {
            int b = 0, g = 1, r = 2, a = 3;
            //中间数
            float midval = (float)maxval * 0.5f;
            for (int i = 0; i < imagedata.Length; i += VarPixel)
            {
                //根据高度值val计算彩色RGB
                float val = (float)imagedata[i + r];
                imagedata[i + r] = (byte)Math.Min(255, (int)(val / midval * (float)255));
                imagedata[i + g] = (byte)Math.Max(0, Math.Min(255, (int)((2 - val / midval) * 255)));
                imagedata[i + b] = 0;
                imagedata[i + a] = (byte)(imagedata[i + r] * 0.5);    //透明度等于高度
                //判断是否需要绘制为透视热图
                if (gray)
                {
                    //在彩色热图的基础上根据红色通道数值更改黑色透明度成为透视热图
                    if (imagedata[i + a] == 0)
                    {
                        imagedata[i + r] = 0;
                        imagedata[i + g] = 0;
                        imagedata[i + b] = 0;
                        imagedata[i + a] = 255;
                    }
                    else
                    {
                        imagedata[i + r] = 0;
                        imagedata[i + g] = 0;
                        imagedata[i + b] = 0;
                        imagedata[i + a] = (byte)(255 - imagedata[i + a]);
                    }
                }
                //彩色热图需要合并归一化多人热图（使用红色覆盖绿色）
                else
                {
                    //透明区域
                    if (imagedata[i + a] == 0)
                    {
                        imagedata[i + r] = imagedata[i + r];
                        imagedata[i + g] = imagedata[i + g];
                        imagedata[i + b] = imagedata[i + b];
                        imagedata[i + a] = imagedata[i + a];
                    }
                    //使用颜色更红的覆盖
                    else if ((imagedata[i + r] - imagedata[i + g]) > (imagedata[i + r] - imagedata[i + g]))
                    {
                        imagedata[i + r] = imagedata[i + r];
                        imagedata[i + g] = imagedata[i + g];
                        imagedata[i + b] = imagedata[i + b];
                        imagedata[i + a] = imagedata[i + a];
                    }
                }
            }
        }
        #endregion

        #region 方法
        public bool Init()
        {
            bool result = false;
            try
            {
                //D2D图片
                D2DBitmap = new SharpDX.WIC.Bitmap(D2DImageFactory, (int)Width, (int)Height, SharpDX.WIC.PixelFormat.Format32bppBGR, BitmapCreateCacheOption.CacheOnLoad);

                // 渲染目标属性
                RenderTargetProperties RenderTargetProperties = new RenderTargetProperties(RenderTargetType.Default, new SharpDX.Direct2D1.PixelFormat(Format.Unknown, SharpDX.Direct2D1.AlphaMode.Unknown), 0, 0, RenderTargetUsage.None, FeatureLevel.Level_DEFAULT);
                D2DRenderTarget = new WicRenderTarget(D2DFactory, D2DBitmap, RenderTargetProperties);
                result = true;
            }
            catch (Exception ex)
            {
                Trace.TraceError(ex.Message);
            }
            return result;
        }

        public void Render(List<Point> points)
        {
            try
            {
                this.D2DRenderTarget.BeginDraw();
                this.D2DRenderTarget.Clear(new RawColor4(0, 0, 0, 0));
                points.ForEach(p =>
                 {
                     var ellipse = new Ellipse(new RawVector2((float)p.X, (float)p.Y), 10, 10);
                     var brush = new SharpDX.Direct2D1.SolidColorBrush(D2DRenderTarget, new RawColor4(Brushes.Red.Color.ScR, Brushes.Red.Color.ScG, Brushes.Red.Color.ScB, Brushes.Red.Color.ScA));
                     this.D2DRenderTarget.FillEllipse(ellipse, brush);
                 });

                this.D2DRenderTarget.EndDraw();

                byte[] imagesData = new byte[(int)(VarPixel * Width * Height)];
                D2DBitmap.CopyPixels(imagesData, this.VarPixel * (int)Width);

                System.Drawing.Bitmap bitmap1 = new System.Drawing.Bitmap((int)Width, (int)Height);

                //Normalization(ref imagesData);

                WriteableBitmap bitmap = new WriteableBitmap((int)Width, (int)Height, 96, 96, PixelFormats.Bgra32, null);
                bitmap.Lock();
                Marshal.Copy(imagesData, 0, bitmap.BackBuffer, imagesData.Length);
                bitmap.AddDirtyRect(new Int32Rect(0, 0, (int)Width, (int)Height));
                bitmap.Unlock();

                var context = drawingVisual.RenderOpen();
                context.DrawImage(bitmap, new Rect(0, 0, this.Width, this.Height));
                context.Close();
            }
            catch (Exception ex)
            {
                Trace.TraceError(ex.Message);
            }
        }



        #endregion
    }
}
